home *** CD-ROM | disk | FTP | other *** search
/ AGA Toolkit '97 / The AGA Toolkit '97.iso / programming / debug / calls / scan.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-09-07  |  8.1 KB  |  343 lines

  1. /*
  2.  * scan.c -- a simple scanner for C, pulls out the function
  3.  *    calling pattern (all by KSB)
  4.  */
  5.  
  6. #ifdef pdp11
  7. #include <sys/types.h>
  8. #endif
  9. #include <ctype.h>
  10. #include <stdio.h>
  11. #include <strings.h>
  12. #ifdef __amigados__
  13. #include <stdlib.h>
  14. #endif
  15. #define strsave(X)      strcpy((char *)malloc(strlen((X))+1), (X))
  16.  
  17. #include "scan.h"
  18. #include "main.h"
  19.  
  20. int c;                /* parser look ahead            */
  21. FILE *input;            /* our input file pointer        */
  22. HASH *pHTRoot[2] =        /* our list of idents            */
  23.     {nilHASH, nilHASH};
  24. static char
  25.     ASM[] = "asm",          AUTO[] = "auto",        BREAK[] = "break",
  26.     CASE[] = "case",        CHAR[] = "char",        CONST[] = "const",
  27.     CONTINUE[] = "continue",DEFAULT[] = "default",  DO[] = "do",
  28.     DOUBLE[] = "double",    ELSE[] = "else",        ENUM[] = "enum",
  29.     EXTERN[] = "extern",    FLOAT[] = "float",      FOR[] = "for",
  30.     FORTRAN[] = "fortran",  GOTO[] = "goto",        IF[] = "if",
  31.     INT[] = "int",          LONG[] = "long",
  32.     REGISTER[] = "register",RETURN[] = "return",    SHORT[] = "short",
  33.     SIGNED[] = "signed",    SIZEOF[] = "sizeof",    STATIC[] = "static",
  34.     STRUCT[] = "struct",    SWITCH[] = "switch",
  35.     TYPEDEF[] = "typedef",  UNION[] = "union",
  36.     UNSIGNED[] = "unsigned",VOID[] = "void",
  37.     VOLATILE[] = "volatile",WHILE[] = "while";
  38.  
  39. HASH *
  40. newHASH()       /* get a new hash node                                  */
  41. {
  42.     extern char *calloc();
  43.     register HASH *pHTRet;
  44.     static HASH *pHTQueue = nilHASH;
  45.  
  46.     if (nilHASH == pHTQueue) {
  47.         if (!(pHTRet = (HASH *)calloc(BUCKET, sizeof(HASH)))) {
  48.             (void) fprintf(stderr, "out of mem\n");
  49.             exit(2);
  50.         }
  51.         pHTQueue = (pHTRet+(BUCKET-1))->pHTnext = pHTRet;
  52.     }
  53.     pHTRet = pHTQueue;
  54.     pHTQueue = pHTRet->pHTnext ? nilHASH : pHTRet+1;
  55.     return pHTRet;
  56. }
  57.  
  58. HASH *
  59. search(name, Localp, pchFile)   /* translate name to hash node          */
  60. register char *name;
  61. int Localp;            /* -> trying to make a local def    */
  62. char *pchFile;
  63. {
  64.     register HASH **ppHT, *pHT;
  65.     register int i = 1;
  66.  
  67.     ppHT = & pHTRoot[1];    /* first search statics */
  68.     while((pHT = *ppHT) && (i = strcmp(pHT->pchname, name)) <= 0) {
  69.         if (0 == i && 0 == strcmp(pchFile, pHT->pchfile))
  70.             break;    /* found a visible static function    */
  71.         ppHT = & pHT->pHTnext;
  72.         i = 1;
  73.     }
  74.  
  75.     if (0 != i && ! Localp) {
  76.         ppHT = & pHTRoot[0];
  77.         while((pHT = *ppHT) && (i = strcmp(pHT->pchname, name)) < 0)
  78.             ppHT = & pHT->pHTnext;
  79.     }
  80.  
  81.     if (0 != i) {
  82.         pHT = newHASH();
  83.         pHT->pchname = strsave(name);
  84. #ifdef BADCALLOC        /* calloc does not zero mem?        */
  85.         pHT->pchfile = (char *) 0;
  86.         pHT->listp = 0;
  87.         pHT->calledp = 0;
  88.         pHT->pINcalls = nilINST;
  89. #endif BADCALLOC
  90.         pHT->localp = Localp;
  91.         pHT->pHTnext = *ppHT;
  92.         *ppHT = pHT;
  93.     }
  94.     return pHT;
  95. }
  96.  
  97. /*
  98.  * here we don't assume that cpp takes out comments, really
  99.  * paranoid of us, but I think that way
  100.  * f is a flag we use to make the look ahead come out right
  101.  * in all cases
  102.  */
  103. void
  104. eatwhite(f)     /* skip blanks, comments, "strings", 'chars' in input   */
  105. register int f;
  106. {
  107.     if (f)
  108.         c = getc(input);
  109.     for(/* void */; /* c != EOF */; c = getc(input)) {
  110.         if (isspace(c) || c == '\b') {
  111.             continue;
  112.         } else if ('/' == c) {          /* start of comment? */
  113.             if ('*' == (c = getc(input))) {
  114.                 c = getc(input);        /* eat comment */
  115.                 for(;;) {
  116.                     while (c != '*')
  117.                         c = getc(input);
  118.                     if ('/' == (c = getc(input)))
  119.                         break;
  120.                 }
  121.             } else {
  122.                 ungetc(c, input);
  123.                 c = '/';
  124.                 break;
  125.             }
  126.         } else if ('\'' == c || '"' == c) {
  127.             while(c != (f = getc(input))) {
  128.                 if ('\\' == f)
  129.                     getc(input);
  130.             }
  131.         } else if ('#' == c) {
  132.             while ('\n' != getc(input))
  133.                 /* void */;
  134.         } else {
  135.             break;
  136.         }
  137.     }
  138. }
  139.  
  140. void
  141. balance(l, r)   /* find balancing character                             */
  142. register int l, r;
  143. {
  144.     register int brace = 1;
  145.  
  146.     do
  147.         eatwhite(1);
  148.     while (brace += (l == c) - (r == c));
  149. }
  150.  
  151. int
  152. getid(sb, ppchToken)    /* return 0 = var, 1 == func, 2 == keyword      */
  153. register char *sb;
  154. char **ppchToken;
  155. {
  156.     static char *keywords[] = {
  157.         ASM, AUTO, BREAK, CASE, CHAR, CONST, CONTINUE, DEFAULT,
  158.         DO, DOUBLE, ELSE, ENUM, EXTERN, FLOAT, FOR,
  159.         FORTRAN, GOTO, IF, INT, LONG, REGISTER,
  160.         RETURN, SHORT, SIGNED, SIZEOF, STATIC, STRUCT, SWITCH,
  161.         TYPEDEF, UNION, UNSIGNED, VOID, VOLATILE, WHILE, (char *)0
  162.     };
  163.     register int i = 0;
  164.     register char **psbKey = keywords;
  165.  
  166.     do {
  167.         if (i < MAXCHARS)
  168.             sb[i++] = c;
  169.         c = getc(input);
  170.     } while (isalpha(c) || isdigit(c) || '_' == c);
  171.     sb[i] = '\000';         /* buffer really goes to MAXCHARS+1     */
  172.     eatwhite(0);    /* c == next char after id */
  173.  
  174.     while (*psbKey && 0 != strcmp(*psbKey, sb))
  175.         ++psbKey;
  176.  
  177.     if (*psbKey) {
  178.         *ppchToken = *psbKey;
  179.         return 2;
  180.     }
  181.  
  182.     return LPAREN == c;
  183. }
  184.  
  185. void
  186. eatdecl(sb)     /* eat anything that starts with any keyword listed     */
  187. register char *sb;
  188. {
  189.     static char *which[] = {    /* keywords mark a declaration    */
  190.         AUTO, CHAR, CONST, DOUBLE, ENUM, EXTERN, FLOAT, INT,
  191.         LONG, REGISTER, SHORT, SIGNED, STATIC, STRUCT, TYPEDEF, UNION,
  192.         UNSIGNED, VOID, VOLATILE, (char *) 0};
  193.     register char **psb = which;
  194.  
  195.     while(*psb)
  196.         if (*psb++ == sb)
  197.             break;
  198.     if (*psb) {
  199.         while ('=' != c && ';' != c && RPAREN != c) {
  200.             if (LCURLY == c)
  201.                 balance(LCURLY, RCURLY);
  202.             else if (LPAREN == c) {
  203.                 balance(LPAREN, RPAREN);
  204.             }
  205.             eatwhite(1);
  206.         }
  207.     }
  208. }
  209.  
  210. INST *
  211. newINST()       /* get a new instaniation  node                         */
  212. {
  213.     extern char *calloc();
  214.     register INST *pINRet;
  215.     static INST *pINQueue = nilINST;
  216.  
  217.     if (nilINST == pINQueue) {
  218.         if (!(pINRet = (INST *)calloc(BUCKET, sizeof(INST)))) {
  219.             (void) fprintf(stderr, "out of mem\n");
  220.             exit(2);
  221.         }
  222.         pINQueue = (pINRet+(BUCKET-1))->pINnext = pINRet;
  223.     }
  224.     pINRet = pINQueue;
  225.     pINQueue = pINRet->pINnext ? nilINST : pINRet+1;
  226.     return pINRet;
  227. }
  228.  
  229. void
  230. level2(pHTCaller, pchFile)      /* inside a function looking for calls  */
  231. HASH *pHTCaller;
  232. char *pchFile;
  233. {
  234.     static char buffer[MAXCHARS+1];
  235.     register struct INnode *pINLoop;
  236.     register int brace = 0;
  237.     register HASH *pHTFound;
  238.     register struct INnode **ppIN = & (pHTCaller->pINcalls);
  239.     register int declp = 1;     /* eating declarations        */
  240.     auto char *pchToken;
  241.  
  242.     while (brace || declp) {
  243.         if (isalpha(c) || '_' == c) {
  244.             switch (getid(buffer, & pchToken)) {
  245.             case 1:
  246.                 pHTFound = search(buffer, 0, pchFile);
  247.                 if (Allp)
  248.                     goto regardless;
  249.                 for(pINLoop = pHTCaller->pINcalls;
  250.                     pINLoop;
  251.                     pINLoop = pINLoop->pINnext)
  252.                     if (pHTFound == pINLoop->pHTname)
  253.                         break;
  254.                 if (! pINLoop) {
  255.             regardless:
  256.                     pINLoop = *ppIN = newINST();
  257.                     pINLoop->pHTname = pHTFound;
  258.                     ppIN = & pINLoop->pINnext;
  259.                 }
  260.                 ++pHTFound->calledp;
  261.                 break;
  262.             case 2:
  263.                 eatdecl(pchToken);
  264.                 /* fall through */
  265.             case 0:
  266.                 break;
  267.             }
  268.         } else {
  269.             if (LCURLY == c)
  270.                 declp = 0, ++brace;
  271.             else if (RCURLY == c)
  272.                 --brace;
  273.             eatwhite(1);
  274.         }
  275.     }
  276.     *ppIN = nilINST;
  277. }
  278.  
  279. void
  280. level1(filename)        /* in a C source program, looking for fnx(){..} */
  281. register char *filename;
  282. {
  283.     static char buffer[MAXCHARS+1];
  284.     static char *pchToken;
  285.     register HASH *pHTTemp;
  286.     register int parens = 0;
  287.     register int Localp = 0;
  288.  
  289.     c = ' ';
  290.  
  291.     do {        /* looking to a function decl    */
  292.         if (isalpha(c) || '_' == c) {
  293.             switch (getid(buffer, & pchToken)) {
  294.             case 1:
  295.                 while (parens += (LPAREN == c) - (RPAREN == c))
  296.                     eatwhite(1);
  297.                 for (;;) {      /* eat complex stuff    */
  298.                     eatwhite(1);
  299.                     if (LPAREN == c) {
  300.                         balance(LPAREN, RPAREN);
  301.                         continue;
  302.                     } else if (LBRACK == c) {
  303.                         balance(LBRACK, RBRACK);
  304.                         continue;
  305.                     } else {
  306.                         break;
  307.                     }
  308.                 }
  309.                 pHTTemp = search(buffer, Localp, filename);
  310.                 if (',' == c || ';' == c) {
  311.                     Localp = 0;
  312.                     break;
  313.                 }
  314.                 if (pHTTemp->pchfile && pHTTemp->pchfile != sbCmd &&
  315.                     (pHTTemp->pchfile == filename ||
  316.                     0 != strcmp(pHTTemp->pchfile, filename))) {
  317.                     fprintf(stderr, "%s is multiply defined [%s, %s]\n", pHTTemp->pchname, pHTTemp->pchfile, filename);
  318.                     exit(5);
  319.                 } else {
  320.                     pHTTemp->pchfile = filename;
  321.                     Localp = 0;
  322.                     level2(pHTTemp, filename);
  323.                 }
  324.                 continue;
  325.             case 2:
  326.                 if (STATIC == pchToken)
  327.                     Localp = 1;
  328.             case 0:
  329.                 continue;
  330.             }
  331.         } else if (LCURLY == c) {
  332.             balance(LCURLY, RCURLY);
  333.         } else if (LPAREN == c) {
  334.             ++parens;
  335.         } else if (RPAREN == c) {
  336.             --parens;
  337.         } else if ('*' != c) {
  338.             Localp = 0;
  339.         }
  340.         eatwhite(1);
  341.     } while (EOF != c);
  342. }
  343.